#include <iostream>

using namespace std;

// 装饰器的核心是组件可以嵌套组件,
// 且两个组件必须是同个基类的(俄罗斯套娃)

// 组件基类
class Component {
public:
    virtual ~Component() = default;

public:
    virtual void doSomeThing() = 0;
};

// 装饰器基类
class Decorator : public Component {
public:
    Decorator() = default;

    explicit Decorator(Component *component) : component(component) {}

    ~Decorator() override = default;

private:
    Component *component{};

public:
    void doSomeThing() override {
        component->doSomeThing();
    }
};

class ConcreteComponentA : public Component {
public:
    ConcreteComponentA() = default;

    ~ConcreteComponentA() override = default;

public:
    void doSomeThing() override {
        cout << "Concrete Component A Do Some Thing!" << endl;
    }
};

class ConcreteComponentB : public Component {
public:
    ConcreteComponentB() = default;

    ~ConcreteComponentB() override = default;

public:
    void doSomeThing() override {
        cout << "Concrete Component B Do Some Thing!" << endl;
    }
};

class ConcreteDecoratorA : public Decorator {
public:
    ConcreteDecoratorA() = default;

    explicit ConcreteDecoratorA(Component *component) : Decorator(component) {}

    ~ConcreteDecoratorA() override = default;

public:
    void doSomeThing() override {
        Decorator::doSomeThing();
        cout << "Concrete Decorator A Do Some Thing!" << endl;
    }
};

class ConcreteDecoratorB : public Decorator {
public:
    ConcreteDecoratorB() = default;

    explicit ConcreteDecoratorB(Component *component) : Decorator(component) {}

    ~ConcreteDecoratorB() override = default;

public:
    void doSomeThing() override {
        Decorator::doSomeThing();
        cout << "Concrete Decorator B Do Some Thing!" << endl;
    }
};

void test01() {
    Component *componentA = nullptr;

    componentA = new ConcreteComponentA();
    componentA->doSomeThing();

    cout << endl;

    componentA = new ConcreteDecoratorA(componentA);
    componentA->doSomeThing();

    cout << endl;
}

void test02() {
    Component *componentB = nullptr;

    componentB = new ConcreteComponentB();
    componentB->doSomeThing();

    cout << endl;

    componentB = new ConcreteDecoratorB(componentB);
    componentB = new ConcreteDecoratorA(componentB);
    componentB->doSomeThing();

    cout << endl;
}

int main() {
    test01();

    test02();

    return 0;
}